/**
 * Compiler 主要负责模块构建和文件输出
 */

const { getAST, getDependencies, transform } = require('./parser');
const path = require('path');
const fs = require('fs');

module.exports = class Compiler {
  constructor(options) {
    const { entry, output } = options;
    this.entry = entry;
    this.output = output;
    this.modules = [];
  }

  run() {
    const entryModule = this.buildModule(this.entry, true);
    this.modules.push(entryModule);
    // 遍历所有依赖，递归构建所有依赖的依赖，就能得到所有模块
    this.modules.forEach((_module) => {
      _module.dependencies.forEach((dependency) => {
        this.modules.push(this.buildModule(dependency));
      });
    })
    // console.log(this.modules);

    this.emitFiles();
  }

  buildModule(filename, isEntry) {
    let ast;
    if (isEntry) {
      // 如果是入口文件，直接转换为AST
      // 入口模块要求是绝对路径，所以直接传入即可
      ast = getAST(filename);
    } else {
      // 如果不是入口文件，就是模块依赖
      // 先将相对路径转换为绝对路径，process.cwd()表示当前项目根目录
      const absolutePath = path.join(process.cwd(), './src', filename);
      ast = getAST(absolutePath);
    }
    return {
      filename,
      dependencies: getDependencies(ast),
      source: transform(ast),
    };
  }

  emitFiles() {
    const outputPath = path.join(this.output.path, this.output.filename);

    let modules = '';
    this.modules.forEach((_module) => {
      modules += `'${_module.filename}': function (require, module, exports) { ${_module.source} },`;
    })

    const bundle = `(function(modules) {
      function require(filename) {
        var fn = modules[filename];
        var module = { exports: {}};
        fn(require, module, module.exports);
        return module.exports;
      }
        require('${this.entry}');
    })({${modules}})`;
    // console.log(bundle);

    fs.writeFileSync(outputPath, bundle, 'utf-8');
  }
};